(function() {

// 只初始化一遍
if(window.ftclient) return;

// 64个字符和他们的index表
var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".split('');
var CHARS_MAP = new Array(128); for(var i =0 ; i < 64; CHARS_MAP[CHARS[i].charCodeAt(0)] = i++);

/** 加密 src必须都是ascii字符,可以先用encodeURIComponent编码 */
var encrypt = function(src) {
	var seqSet = 0;
	for (var i = 0; i < 16; i++) {
		var seq = parseInt(Math.random() * 31);
		if ((seqSet & (1 << seq)) > 0) continue;
		seqSet |= 1 << seq;
	}
	var ret = [], status = 0, left = 0, index = 0;
	for(var i = 0; i < src.length; i++) {
		var b = src.charCodeAt(i);
		switch (status) {
		case 0:
			index = (b >>> 2) & 0x3F;
			if((seqSet & (1 << index)) > 0 || (seqSet & (1 << (63 - index))) > 0) index = 63 - index;
			ret.push(CHARS[index]);
			left |= (b & 0x03) << 4;
			status = 1;
			break;
		case 1:
			left |= (b >>> 4) & 0x0F;
			index = left;
			if((seqSet & (1 << index)) > 0 || (seqSet & (1 << (63 - index))) > 0) index = 63 - index;
			ret.push(CHARS[index]);
			left = (b & 0x0F) << 2;
			status = 2;
			break;
		case 2:
			left |= (b >>> 6) & 0x03;
			index = left;
			if((seqSet & (1 << index)) > 0 || (seqSet & (1 << (63 - index))) > 0) index = 63 - index;
			ret.push(CHARS[index]);
			index = b & 0x3F;
			if((seqSet & (1 << index)) > 0 || (seqSet & (1 << (63 - index))) > 0) index = 63 - index;
			ret.push(CHARS[index]);
			status = left = index = 0;
		}
	}
	if (status > 0) {
		index = left;
		if((seqSet & (1 << index)) > 0 || (seqSet & (1 << (63 - index))) > 0) index = 63 - index;
		ret.push(CHARS[index]);
	}
	return [seqSet.toString(), ret.join('')];
};

/** 解密 返回的都是ascii字符 */
var decrypt = function (salt, src) {
	var seqSet = parseInt(salt), status = 0, dstIndex = 0, len = src.length * 6 >>> 3;
	var dst = new Array(len), str = [];
	for(var i = 0; i < src.length; i++) {
		var index = CHARS_MAP[src[i].charCodeAt(0)];
		if((seqSet & (1 << index)) > 0 || (seqSet & (1 << (63 - index))) > 0) index = 63 - index;
		switch(status) {
		case 0:
			dst[dstIndex] |= index << 2;
			status = 1;
			break;
		case 1:
			dst[dstIndex] |= (index >>> 4) & 0x03;
			str.push(String.fromCharCode(dst[dstIndex++]));
			if(len == dstIndex) break;
			dst[dstIndex] |= (index & 0x0F) << 4;
			status = 2;
			break;
		case 2:
			dst[dstIndex] |= (index >>> 2) & 0x0F;
			str.push(String.fromCharCode(dst[dstIndex++]));
			if(len == dstIndex) break;
			dst[dstIndex] |= (index & 0x03) << 6;
			status = 3;
			break;
		case 3:
			dst[dstIndex] |= index;
			str.push(String.fromCharCode(dst[dstIndex++]));
			status = 0;
		}
	}
	return str.join('');
};

if (!window.WebSocket) window.WebSocket = window.MozWebSocket;
if(!window.WebSocket) {

	// 这里考虑退化到ajax的措施
	return;
}

var isMessage = function(msg) {
	return typeof msg === 'object' 
	&& msg.hasOwnProperty('version') && typeof msg.version === 'string' 
	&& msg.hasOwnProperty('type') && typeof msg.type === 'number';
};

// see http://www.w3.org/TR/websockets/#refsWSP
var newSock = function(url, handlers) {
	var sock = new window.WebSocket(url);
	if(typeof handlers === 'object') {
		if(typeof handlers.onopen === 'function') sock.onopen = handlers.onopen;
		if(typeof handlers.onerror === 'function') sock.onerror = handlers.onerror;
		if(typeof handlers.onclose === 'function') sock.onclose = handlers.onclose;
		if(typeof handlers.onmessage === 'function') sock.onmessage = function(e) {
			var msg = e.data;
			if(typeof msg === 'string') {
				if(msg.charAt(0) == '$') {
					var sp = msg.indexOf('_');
					msg = decodeURIComponent(decrypt(msg.substring(1, sp), msg.substring(sp + 1)));
				}
				msg = JSON.parse(msg);
				handlers.onmessage(msg);
			}
		};
	}
	return {
		CONNECTING:0,OPEN:1,CLOSING:2,CLOSED:3,
		getReadyState: function(){return sock.readyState;},
		getBufferedAmount: function(){return sock.bufferedAmount;},
		close: function(code, reason) {
			alert("clew");
			sock.close(code, reason);},
		send: function(data) {
			if(isMessage(data)) {
				var d = [data.version, '-', data.type, '_'];
				if(data.secure === true) {
					var ec = encrypt(encodeURIComponent(JSON.stringify(data)));
					d.push('$');
					d.push(ec[0]);
					d.push('_');
					d.push(ec[1]);
				} else {
					d.push(JSON.stringify(data));
				}
				sock.send(d.join(''));
			} else {
				try{
					sock.send(data);
				}catch (e){

				}
				
			}
		}
	};
};

window.ftclient = {newSock: newSock};
})();